package com.woniuxy.service.impl;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Return;
import com.rabbitmq.client.ReturnCallback;
import com.woniuxy.po.Mail;
import com.woniuxy.service.Publisher;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.lang.model.element.VariableElement;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: mayuhang  <br/>
 * Date: 2021/3/19:11:03  <br/>
 * Description:这边实现了接口，对应接口代码忽略，消息发送端
 */
@Service("publisher")
public class PublisherImpl implements Publisher {
	@Autowired
    RabbitTemplate rabbitTemplate;
	@Override
	public void publishMail(Mail mail) {
		//设置响应回调，如果找不到交换机，则回调ack为false
		rabbitTemplate.setConfirmCallback(confirmCallback);
		//设置返回响应，发送到队列后（或者发送失败），则回调消息至returnsCallback
		rabbitTemplate.setReturnsCallback(returnsCallback);
		//id+时间戳  全局唯一默认是用的uuid
		CorrelationData correlationData = new CorrelationData();
		System.out.println(correlationData.getId());
		rabbitTemplate.convertAndSend("fanout", "", mail,correlationData);
	}
	@Override
	public void sendDirectMail(Mail mail, String routingkey) {
		rabbitTemplate.convertAndSend("direct", routingkey, mail);
	}
	@Override
	public void sendTopicMail(Mail mail, String routingkey) {
		//设置响应回调，如果找不到交换机，则回调ack为false
		rabbitTemplate.setConfirmCallback(confirmCallback);
		//设置返回响应，发送到队列后（或者发送失败），则回调消息至returnsCallback
		rabbitTemplate.setReturnsCallback(returnsCallback);
		rabbitTemplate.convertAndSend("mytopic", routingkey, mail);
	}
	//消息发送到交换机时，routingkey能路由正确队列，触发回调！
	final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
		/**
		 * Description : 回调信息实现  <br/>
		 * ChangeLog : 1. 创建 (2021/3/16 14:43 [mayuhang]);
		 * @param correlationData 相关数据，感兴趣自己打印出来研究
		 * @param ack 相应返回如果交换机收到即刻返回为true
		 * @param cause 原因返回
		 * @return void
		 **/
		@Override
		public void confirm(CorrelationData correlationData, boolean ack, String cause) {
			if(ack){
				System.out.println("-------------------ConfirmCallback,发送到交换机成功------------------------");
				System.out.println("发送成功，进行业务操作....");
				if (correlationData!=null){
					System.out.println("发送成功"+"correlationData全局id为："+correlationData.getId());
				}
			}else {
				System.out.println("-------------------ConfirmCallback,发送到交换机失败------------------------");
				if (correlationData!=null){
					System.out.println("发送确认成功"+"correlationData全局id为："+correlationData.getId());
				}
				System.err.println("失败原因："+cause);
			}
		}
	};
	//从交换机发送到队列，如果队列是否收到都会执行回调，需要手动处理！
	private RabbitTemplate.ReturnsCallback returnsCallback = new RabbitTemplate.ReturnsCallback() {
		@Override
		public void returnedMessage(ReturnedMessage returned) {
			System.err.println("-------------------ReturnsCallback------------------------");
//			System.out.println("ReturnedMessage,该参数具体业务具体使用 ："+returned.toString());
			System.err.println(new String(returned.getMessage().toString())+"消息被退回");
			System.err.println("消息退回原因："+returned.getReplyText());
			System.err.println("路由："+returned.getRoutingKey());
			System.err.println("获得消费者全局唯一标签："+returned.getMessage().getMessageProperties().getHeader("spring_returned_message_correlation"));
		}
	};
	/**
	 * Description : 延迟队列发送消息到交换机，routingkey简单改为lazy.1000 1000为1s延迟  <br/>
	 * ChangeLog : 1. 创建 (2021/3/17 17:30 [mayuhang]);
	 * @param mail
	 * @param exchange 交换机
	 * @param routingkey 队列
	 * @return void
	 **/
	@Override
	public void sendLazyMail(Mail mail,String exchange, String routingkey) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		System.out.println("msg发送时间："+simpleDateFormat.format(new Date()));
		//id+时间戳  全局唯一
		CorrelationData correlationData = new CorrelationData(Math.random()+simpleDateFormat.format(new Date()));
		//设置响应回调，如果找不到交换机，则回调ack为false
		rabbitTemplate.setConfirmCallback(confirmCallback);
		//设置返回响应，发送到队列后（或者发送失败），则回调消息至returnsCallback
		rabbitTemplate.setReturnsCallback(returnsCallback);
		//消息发送
		rabbitTemplate.convertAndSend(exchange, routingkey, mail,
				(message)-> {
					//简单处理routingkey，截取.后面数据为延迟的时间，实际业务中，肯定不会使用这个，可在实体里定义，或者根据业务定义
					String[] split = routingkey.split("\\.");
					int i = Integer.parseInt(split[1]);
					System.out.println("延迟时间：" + i);
					//设置消息持久化
					message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
					//这个底层就是setHeader("x-delay",i);是一样的
					message.getMessageProperties().setHeader("x-delay",i);
					return message;
				}
			,correlationData);
	}
	/**
	 * @author: mayuhang  <br/>
	 * Date: 2021/3/25:15:09  <br/>
	 * Description:发送到normal交换机 测试备用交换机
	 */
	@Override
	public void sendNomalTopicMail(Mail mail, String exchange, String routingkey) {
		//设置响应回调，如果找不到交换机，则回调ack为false
		rabbitTemplate.setConfirmCallback(confirmCallback);
		//设置返回响应，发送到队列后（或者发送失败），则回调消息至returnsCallback
		rabbitTemplate.setReturnsCallback(returnsCallback);
		rabbitTemplate.convertAndSend(exchange, routingkey, mail);
	}
}
